#!/usr/bin/python
# -*- coding: utf-8 -*-
#coding=utf-8

import time
import datetime
import random
import datetimeDemo as tsLog
# https://zhuanlan.zhihu.com/p/519223654

class RecordBase(object):
    # 加上双下划线的就是私有变量，只能在类的内部访问，外部无法访问
    __createTimeStampMs = 0
    __lastModTimeStampMs = 0
    __ctsrID = ''

    # 实际上调用__init__方法之前，也就是新创建的对象对自己进行初始化之前，得先创建出来对象。
    # 所以在__init__方法执行之前，先调用了__new__(cls)方法，这个方法的作用就是根据类(cls)创建一个新的对象。
    # 创建新对象之后，再执行这个新对象的__init__方法，对新对象进行初始化。
    # __new__(cls)的实现过程被隐藏了，但是我们可以重写这个方法，在重写之前需要先调用实现过程。
    # def __new__(cls, *args, **kwargs):
    #     print("RecordBase new")
    #     obj = super().__new__(cls)
    #     return obj

    def __init__(self):
        self.__createTimeStampMs = round(time.time()*1000)
        self.__lastModTimeStampMs = self.__createTimeStampMs
        self.__ctsrID = "{}-{}".format(self.__createTimeStampMs, random.randint(1, 10000))
        #print("RecordBase init")

    def __del__(self):
        # 析构函数，释放对象时使用
        print("RecordBase __del__", id(self))

    def __repr__(self):
        # 打印，转换，给开发者看
        #modTS = self.getModifyTs()
        return f"{self.__ctsrID},createTsMs:{self.__createTimeStampMs}, modifyTsMs:{self.__lastModTimeStampMs}"

    def __str__(self):
        # 打印，给客户看
        return self.__repr__()

    def __call__(self, *args, **kwargs):
        # 如果为一个类编写了该方法，那么在该类的实例后面加括号，可会调用这个方法。
        # 构造方法的执行是由类加括号执行的，即：对象 = 类名()，
        # 而对于call() 方法，是由对象后加括号触发的，即：对象() 或者 类()()
        print('RecordBase __call__')

    # 返回一个由 createTimeStampMs + 随机数的
    def getCTSRID(self):
        return self.__ctsrID

    def getCreatTs(self):
        return self.__createTimeStampMs

    def getModifyTs(self):
        return self.__lastModTimeStampMs
        #modTS = self.lastModTimeStampMs if self.lastModTimeStampMs != 0 else self.__createTimeStampMs
        #return modTS


    @staticmethod
    def testStatic():
        print("testStatic")

    @classmethod
    def testClass(cls):
        print("testClass", cls)

class AccountRecord(RecordBase):
    # 账单名称
    title = ''
    # 账单描述
    content = ''
    # 币种
    moneyKind = 0
    # 某个 moneyKind 币种的最小计量单位为 base，记录金额，比如人民币，1元=100分，当记录1元，这个值记录为 100 (人民币 最小计量单位 分)
    amount = 0

    # def __init__(self):
    #     super().__init__()
    #     print("AccountRecord init")

    def __init__(self, t='', c='', a=0, mk=0):
        super().__init__()
        self.title = t
        self.content = c
        self.amount = int(a)
        self.moneyKind = mk
        self.__comment = ''
        #print("AccountRecord init")

    def __add__(self, other):
        # 加运算
        if not isinstance(other, AccountRecord):
            return Exception('not a AccountRecord instance')
        if self.moneyKind != other.moneyKind:
            return Exception('not same moneyKind value')
        return AccountRecord(t="账单相加",
                             c=self.title+" 加上 "+other.title,
                             a=self.amount+other.amount,
                             mk=self.moneyKind)

    def __sub__(self, other):
        # 减运算
        if not isinstance(other, AccountRecord):
            return Exception('not a AccountRecord instance')
        if self.moneyKind != other.moneyKind :
            return Exception('not same moneyKind value')
        return AccountRecord(t="账单相减",
                             c=self.title+" 减去 "+other.title,
                             a=self.amount-other.amount,
                             mk=self.moneyKind)

    def __repr__(self):
        baseRepr = super().__repr__()
        return f"{baseRepr}, title:{self.title}, moneyKind:{self.moneyKind}, amount:{self.amount}, content:{self.content}, comment:{self.__comment}"

    # property装饰器 三方法
    def getComment(self):
        return self.__comment

    def setComment(self, c):
        if isinstance(c, str):
            self.__comment = c

    def delComment(self):
        self.__comment = ''

    # property装饰器 核心在这句
    comment = property(getComment, setComment, delComment, "备注")

    """
    Python中，标识符后面加圆括号，通常代表执行或调用方法的意思。而在标识符后面加中括号[]，通常代表取值的意思。
    Python设计了getitem()、setitem()、delitem() 这三个特殊成员，用于执行与中括号有关的动作。
    它们分别表示取值、赋值、删除数据。也就是如下的操作：
        a = 标识符[] ：   执行__getitem__方法
        标识符[] = a  ：   执行__setitem__方法
        del 标识符[] ：   执行__delitem__方法
    """
    def __getitem__(self, key):
        #print('__getitem__', key)
        if hasattr(self, key):
            return getattr(self, key)
        if key in self.__dict__:
            return self.__dict__[key]
        return None

    def __setitem__(self, key, value):
        #print('__setitem__', key, value)
        if not isinstance(key, str):
            return False
        if '__' in key:
            return False
        if hasattr(self, key):
            setattr(self, key, value)
            return True
        return False

    def __delitem__(self, key):
        if not isinstance(key, str):
            return False
        if '__' in key:
            return False
        if hasattr(self, key):
            delattr(self, key)
            return True
        return False

def demo():
    tsLog.logTs("classDemo", preNewLineNum=2)
    testRecord = RecordBase()
    testAccount1 = AccountRecord('t1', 'c1', 150)
    testAccount2 = AccountRecord('t2', 'c2', -250)
    testAccount3 = AccountRecord('t2', 'c2', 350, 2)

    # [] 相关 魔法方法
    testAccount1['comment'] = '使用了20元活动红包'
    testAccount1['__lastModTimeStampMs'] = 0
    print(r"testAccount1['comment'] =", testAccount1['comment'])
    print(r"testAccount1['test'] =", testAccount1['test'])
    print("AccountRecord1", testAccount1)
    del testAccount1['comment']
    print("AccountRecord1", testAccount1)

    # property装饰器
    testAccount1.comment = '使用了20元优惠券'
    print('testAccount1.comment = ', testAccount1.comment)

    # 魔法方法 __str__ 测试
    print("RecordBase", testRecord)
    print("AccountRecord1", testAccount1)
    print("AccountRecord2", testAccount2)
    print("AccountRecord3", testAccount3)

    # 魔法方法 __add__ __sub__ 测试
    print("testAccount1 + testRecord -> ", testAccount1 + testRecord)
    print("testAccount1 + testAccount2 -> ", testAccount1 + testAccount2)
    print("testAccount1 + testAccount3 -> ", testAccount1 + testAccount3)

    print("testAccount1 - testRecord -> ", testAccount1 - testRecord)
    print("testAccount1 - testAccount2 -> ", testAccount1 - testAccount2)
    print("testAccount1 - testAccount3 -> ", testAccount1 - testAccount3)

    # 静态方法 和 类方法调用
    RecordBase.testStatic()
    RecordBase.testClass()

    AccountRecord.testStatic()
    AccountRecord.testClass()

    # 魔法方法
    print("__doc__", testAccount1.__doc__)
    print("__module__", testAccount1.__module__)
    print("__class__", testAccount1.__class__)
    
    # 列出类或对象中的所有成员！非常重要和有用的一个属性，Python自建
    print("__dict__", testAccount1.__dict__)

    # test __call__ 是由对象后加括号触发的，即：对象() 或者 类()()
    testAccount1()
    AccountRecord()()

if __name__ == '__main__':
    demo()